diff options
Diffstat (limited to 'src/routes/(app)/reset/[code]/+page.svelte')
| -rw-r--r-- | src/routes/(app)/reset/[code]/+page.svelte | 60 |
1 files changed, 59 insertions, 1 deletions
diff --git a/src/routes/(app)/reset/[code]/+page.svelte b/src/routes/(app)/reset/[code]/+page.svelte index df9d1144..ce43a79d 100644 --- a/src/routes/(app)/reset/[code]/+page.svelte +++ b/src/routes/(app)/reset/[code]/+page.svelte @@ -1,14 +1,71 @@ <script> + import { PUBLIC_RECAPTCHA_SITE_KEY } from "$env/static/public"; + import { browser } from "$app/environment"; + import { onDestroy, onMount, tick } from "svelte"; import { t } from "$lib/translations"; import PasswordInput from "$comp/PasswordInput.svelte"; import Icon from "$comp/Icon.svelte"; import Spinner from "$comp/Spinner.svelte"; import { fly } from "svelte/transition"; import { password } from "$lib/store"; + import { fail } from "$lib/utils"; let { form } = $props(); let email; let loading; + let recaptchaToken = ""; + let recaptchaSiteKey = PUBLIC_RECAPTCHA_SITE_KEY; + let isTor = browser && location.hostname.endsWith(".onion"); + + onMount(() => { + if (!isTor && recaptchaSiteKey) { + let s = document.createElement("script"); + s.src = "https://www.google.com/recaptcha/api.js?render=" + recaptchaSiteKey; + document.head.appendChild(s); + } + }); + + const getRecaptchaToken = () => + new Promise((resolve, reject) => { + if (isTor) return resolve(""); + if (!browser || !grecaptcha) return reject(new Error("captcha unavailable")); + grecaptcha.ready(() => { + grecaptcha + .execute(recaptchaSiteKey, { action: "reset" }) + .then(resolve) + .catch(reject); + }); + }); + + const handleSubmit = async (e) => { + e.preventDefault(); + loading = true; + try { + recaptchaToken = await getRecaptchaToken(); + await tick(); + e.currentTarget.submit(); + } catch (err) { + fail(err.message || "captcha failed"); + loading = false; + } + }; + + onDestroy(() => { + if (!browser) return; + const nodeBadge = document.querySelector(".grecaptcha-badge"); + if (nodeBadge) { + document.body.removeChild(nodeBadge.parentNode); + } + + const scriptSelector = + "script[src='https://www.google.com/recaptcha/api.js?render=" + + recaptchaSiteKey + + "']"; + const script = document.querySelector(scriptSelector); + if (script) { + script.remove(); + } + }); </script> <div class="pt-10"> @@ -30,7 +87,8 @@ </div> {/if} - <form class="space-y-5" method="POST"> + <form class="space-y-5" method="POST" onsubmit={handleSubmit}> + <input type="hidden" name="recaptcha" value={recaptchaToken} /> <PasswordInput bind:value={$password} placeholder={$t("login.password")} |
